
#include "SymbolicExpressionGenerator.h"

#include <sstream>

string SymbolicExpressionGenerator::generateExpression(const string &testFuncName, int m, int n)
{
  string e;
  int i, j, k;
  
  if(testFuncName == "beale")
    return "(1.5-x*(1-y))^2+(2.25-x*(1-y^2))^2+(2.625-x*(1-y^3))^2";
  else if(testFuncName == "biggsexp6")
  {
    for(i = 1; i <= m; i++)
    {
      ostringstream ti(ios_base::out);
      ostringstream yi(ios_base::out);
      
      ti<<"0.1*"<<i;
      yi<<"(exp(-"<<ti.str()<<")-5.0*exp(-10.0*"<<ti.str()<<")+3*exp(-4.0*"<<ti.str()<<"))";
      e += "(x3*exp(-" + ti.str() + "*x1)-x4*exp(-" + ti.str() + "*x2)+x6*exp(-" + ti.str() + "*x5)-" + yi.str() + ")^2";
      
      if(i < m)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "box")
  {
    for(int i = 1; i <= m; i++)
    {
      ostringstream ti(ios_base::out);
      
      ti<<"0.1*"<<i;
      e += "(exp(-" + ti.str() + "*x1)-exp(-" + ti.str() + "*x2)-x3*(exp(-" + ti.str() + ")-exp(-10*" + ti.str() + ")))^2";
      
      if(i < m)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "brownbadlyscaled")
    return "(x-1e6)^2+(y-2e-6)^2+(x*y-2)^2";
  else if(testFuncName == "browndennis")
  {
    for(i = 1; i <= m; i++)
    {
      ostringstream ti(ios_base::out);
      
      ti<<i<<"/5";
      e += "((x1+" + ti.str() + "*x2-exp(" + ti.str() + "))^2+(x3+x4*sin(" + ti.str() + ")-cos(" + ti.str() + "))^2)^2";
      
      if(i < m)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "chebyquad")
  {
    ostringstream xStr(ios_base::out);
    string Tim1; 
    string Ti, prevTi;
    string e;
    string t;
    ostringstream iStr(ios_base::out);
    ostringstream nStr(ios_base::out); 
    
    nStr<<n;
    
    for(i = 1; i <= m; i++)
    {
      string sumStr;
      t = "";
      
      for(j = 1; j <= n; j++)
      {
        Tim1 = "1.0";
        xStr.str("");
        xStr<<"x"<<j;
        Ti = xStr.str();
        for(k = 2; k <= i; k++)
        {
          prevTi = Ti;
          Ti = "2.0*(" + xStr.str() + "*(" + Ti + "))-(" + Tim1 + ")";
          Tim1 = prevTi;
        }
        
        t += Ti;
        if(j < n)
          t += "+";
      }
      
      t = "(" + t + ")/" + nStr.str();
      
      if(i % 2 == 0)
      {
        iStr.str("");
        iStr<<i;
        t += "+1.0/(" + iStr.str() + "^2-1.0)";
      }
      
      e += "(" + t + ")^2";
      if(i < m)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "extendedpowellsingular")
  {
    string fix;
    ostringstream iStr(ios_base::out);
    ostringstream iStr1(ios_base::out);
    ostringstream iStr2(ios_base::out);
    ostringstream iStr3(ios_base::out);   
    
    for(int i = 0; i < n; i += 4)
    {
      iStr.str("");
      iStr<<i;
      iStr1.str("");
      iStr1<<(i+1);
      iStr2.str("");
      iStr2<<(i+2);
      iStr3.str("");
      iStr3<<(i+3);
      
      fix = "x" + iStr.str() + "+10.0*x" + iStr1.str();
      e += "(" + fix + ")^2+";
      
      fix = "x" + iStr2.str() + "-x" + iStr3.str();
      e += "5.0*(" + fix + ")^2+";
      
      fix = "(x" + iStr1.str() + "+2.0*x" + iStr2.str() + ")^2";
      e += "(" + fix + ")^2+";
      
      fix = "(x" + iStr.str() + "-x" + iStr3.str() + ")^2";
      e += "10.0*(" + fix + ")^2";
      
      if(i < n - 4)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "extendedrosenbrock")
  {
    for(i = 1; i < n; i+=2)
    {
      string term1, term2;
      ostringstream xStr1(ios_base::out);
      ostringstream xStr2(ios_base::out);
      
      xStr1<<"x"<<i;
      xStr2<<"x"<<i+1;
      
      term1 = "100*(" + xStr1.str() + "*" + xStr1.str() + "-" + xStr2.str() + ")*(" + xStr1.str() + "*" + xStr1.str() + "-" + xStr2.str() + ")";
      term2 = "(1-" + xStr1.str() + ")*(1-" + xStr1.str() + ")";
      e += term1 + "+" + term2;
      
      if(i < n - 1)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "gaussian")
  {
    const double y[] = { 0.0009, 0.0044, 0.0175, 0.0540, 0.1295, 0.2420, 0.3521, 0.3989, 
        0.3521, 0.2420, 0.1295, 0.0540, 0.0175, 0.0044, 0.0009 };
    
    for(i = 1; i <= 15; i++)
    {
      ostringstream ti(ios_base::out);
      ostringstream yi(ios_base::out);
      
      ti<<"(8-"<<i<<")/2";
      yi<<y[i - 1];
      e += "(x1*exp((-x2*(" + ti.str() + "-x3)^2)/2)-" + yi.str() +")^2";
      
      if(i < 15)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "gulf")
  {
    for(int i = 1; i <= m; i++)
    {
      ostringstream ti(ios_base::out);
      ostringstream yi(ios_base::out);
      ostringstream mi(ios_base::out);
      
      ti<<i<<"/100";
      yi<<"(25+(-50*log("<<ti.str()<<"))^(2/3))";
      mi<<m*i;
      e += "(exp(-abs(" + yi.str() + "-x2)^x3/x1)-" + ti.str() + ")^2";
      
      if(i < m)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "helicalvalley")
  {
    string atanTerm = "1/(2*pi)*atan(x2/x1)";
    e += "100.0*(step(x1)*" + atanTerm + "+step(-x1)*(" + atanTerm + "+0.5))^2+";
    
    e += "100.0*(sqrt(x1^2+x2^2) - 1.0)^2+";
    e += "x3^2";
    
    return e;
  }
  else if(testFuncName == "penaltyfunctionI")
  {
    string fix;
    int i;
    ostringstream iStr(ios_base::out);
    
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      fix = "x" + iStr.str() + "-1.0";
      e += "10^-5*(" + fix + ")^2+";
    }
    
    fix = "";
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      fix += "x" + iStr.str() + "^2+";
    }
    fix += "-0.25";
    
    e += "(" + fix + ")^2";
    
    return e;
  }
  else if(testFuncName == "penaltyfunctionII")
  {
    string fix;
    int i;
    ostringstream iStr(ios_base::out);
    ostringstream im1Str(ios_base::out);
    string yi;
    ostringstream nStr(ios_base::out);
    ostringstream tmpStr(ios_base::out); 
    string sumStr;
    
    e += "(x1-0.2)^2+";
    
    for(i = 2; i <= n; i++)
    {
      fix = "";
      
      iStr.str("");
      iStr<<i;
      im1Str.str("");
      im1Str<<(i-1);
      
      yi = "exp(" + iStr.str() + "/10)+" + "exp(" + im1Str.str() + "/10)";
      
      fix += "exp(x" + iStr.str() + "/10)+";
      fix += "exp(x" + im1Str.str() + "/10)-";
      fix += "(" + yi + ")";
      
      e += "10^-5*(" + fix + ")^2+";
    }
    
    nStr<<n;
    
    for(i = n + 1; i < 2 * n; i++)
    {
      fix = "";
      
      iStr.str("");
      iStr<<i;
      im1Str.str("");
      im1Str<<(i-1);
      tmpStr.str("");
      tmpStr<<(i-n+1);
      
      fix += "exp((x" + tmpStr.str() + ")/10)-exp(-1/10)";
      
      e += "10^-5*(" + fix + ")^2+";
    }
    
    for(i = 1; i <= n; i++)
    {
      tmpStr.str("");
      tmpStr<<(n - i + 1);
      iStr.str("");
      iStr<<i;
      
      sumStr += tmpStr.str() + "*x" + iStr.str() + "^2+";
    }
    
    sumStr += "-1";
    
    e += "(" + sumStr + ")^2";
    
    return e;
  }
  else if(testFuncName == "powellbadlyscaled")
    return "(1e4*x*y-1)^2+(exp(-x)+exp(-y)-1.0001)^2";
  else if(testFuncName == "trigonometric")
  {
    string fix;
    int i;
    ostringstream nStr(ios_base::out);
    ostringstream iStr(ios_base::out);
    ostringstream jStr(ios_base::out); 
    
    nStr<<n;
    
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      
      fix = "";
      fix += nStr.str() + "-(";
      
      for(int j = 1; j <= n; j++)
      {
        jStr.str("");
        jStr<<j;
        fix += "cos(x" + jStr.str() + ")";
        if(j < n)
          fix += "+";
      }
      
      fix += ")+" + iStr.str() + "*(1-cos(x" + iStr.str() + "))-sin(x" + iStr.str() + ")";
      
      e += "(" + fix + ")^2";
      if(i < n)
        e += "+";
    }
    
    return e;
  }
  else if(testFuncName == "variablydimensioned")
  {
    ostringstream iStr(ios_base::out);
    string s;
    
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      e += "(x" + iStr.str() + "-1)^2";
      if(i < n)
        e += "+";
    }    
    
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      s += iStr.str() + "*(x" + iStr.str() + "-1)";
      if(i < n)
        s += "+";
    }
    e += "+(" + s + ")^2";
    
    s = "";
    for(i = 1; i <= n; i++)
    {
      iStr.str("");
      iStr<<i;
      s += iStr.str() + "*(x" + iStr.str() + "-1)";
      if(i < n)
        s += "+";
    }
    e += "+(" + s + ")^4";
    
    return e;
  }
  else if(testFuncName == "watson")
  {
    for(i = 1; i <= 29; i++)
    {
      ostringstream ti(ios_base::out);
      ostringstream sum1(ios_base::out);
      ostringstream sum2(ios_base::out);
      
      ti<<i<<"/29";
      
      for(j = 2; j <= n; j++)
      {     
        sum1<<"("<<j<<"-1)*x"<<j<<"*("<<ti.str()<<")^("<<j<<"-2"<<")";
        if(j < n)
          sum1<<"+";
      }     
      
      for(j = 1; j <= n; j++)
      {     
        sum2<<"x"<<j<<"*("<<ti.str()<<")^("<<j<<"-1)";
        if(j < n)
          sum2<<"+";
      }
      
      e += "(" + sum1.str() + "-(" + sum2.str() + ")^2-1)^2";
      e += "+";
    }
    
    e += "x1^2+(x2-x1^2-1)^2";
    
    return e;
  }
  else if(testFuncName == "wood")
  {
    e += "100*(x2-x1^2)^2+";
    e += "(1-x1)^2+";
    e += "90*(x4-x3^2)^2+";
    e += "(1-x3)^2+";
    e += "10*(x2+x4-2)^2+";
    e += "1/10*(x2-x4)^2";
    
    return e;
  }
  else
    return "";
}
